#pragma once

#include "ResourceLoader.h"
#include "Resource.h"
#include "SDLTexture.h"
#include "XMLNode.h"

struct SDL_Texture;

namespace ZeEngine
{
    class ISDLWindow;

    class ResourceManager
    {
        //Key is the name of the resource
        typedef std::map<std::string, Resource*> ResourceMap;
        typedef std::pair<std::string, Resource*> ResourceMapPair;

        //Key is the group that the resource is in
        typedef std::map<std::string, ResourceMap*> ResourceGroup;
        typedef std::pair<std::string, ResourceMap*> ResourceGroupPair;

        friend class GameEngine;

    public:  
        ~ResourceManager();
        
        void AddResourceFile(const std::string& strResourceFile);
        void LoadResourceGroup(const std::string& strGroup);

        void UnloadResourceGroup(const std::string& strGroup);

        void AddResourceToMap(XMLNodeList& groups, const std::string& strResource, const std::string& strResourceFile);

        template <typename T>
        T* GetResource(const std::string& strName, const std::string& strGroup)
        {
            T* pResource = NULL;
            auto it = m_resources.find(strGroup);

            if (it != m_resources.end())
            {
                auto jt = it->second->find(strName);

                if (jt != it->second->end())
                {
                    pResource = static_cast<T*>(jt->second);
                }
            }

            return pResource;
        }

    private:

        template <typename T>
        T* LoadResource(const std::string& strPath, const std::string& strName, const std::string& strGroup)
        {
            T* pResource = CreateResource<T>(strPath, strName, strGroup);

            if (pResource != NULL)
            {
                pResource->Load();
            }

            return pResource;
        }

        template <typename T>
        T* CreateResource(const std::string& strPath, const std::string& strName, const std::string& strGroup)
        {
            T* pResource = GetResource<T>(strName, strGroup);

            if (pResource == NULL)
            {
                pResource = new T(strPath, strName, strGroup);

                if (pResource && m_pResourceLoader)
                {
                    InsertResourceInMap(strName, strGroup, pResource);                   
                }
            }

            return pResource;
        }

        void InsertResourceInMap(const std::string& strName, const std::string& strGroup, Resource* pResource);
        ResourceMap* CreateGroupInMap(const std::string& strGroup);

        void SetResourceLoader(std::unique_ptr<ResourceLoader> resourceLoader);
        ResourceManager();

    private:
        std::unique_ptr<ResourceLoader> m_pResourceLoader;

        ResourceGroup m_resources;
    };
}

